﻿using System;
using System.Configuration;
using System.Data.SqlClient;
using System.Linq;
using System.Net.Http;
using System.Threading;
using AlipaySDK.Dto.Payment;
using AlipaySDK.Helper;
using Common.Logging;
using In.Api.Dto.YBWs;
using Newtonsoft.Json;
using OutDbContext;
using Rmq.Center;
using User.Api.BizExtensions;
using User.Api.Helpers;
using User.Api.HttpClients;

namespace Out.TaskRunner.RmqWorkers
{
    public class OrderRefundingPickupFailedWorker : IWorker
    {
        private static readonly ILog Logger = LogManager.GetLogger(typeof(OrderRefundingPickupFailedWorker));

        public void Start(CancellationToken ct)
        {
            if (ct.IsCancellationRequested)
            {
                return;
            }

            using (var consumer = new OrderRefundingPickupFailedConsumer())
            {
                consumer.Subscribe((id, count, dt, msg, channel) =>
                {
                    if (msg.OrderType == OrderType.挂号订单)
                    {
                        return ProcessRegOrder(msg.OrderId, channel);
                    }
                    else if (msg.OrderType == OrderType.门诊缴费订单)
                    {
                        return ProcessBillOrder(msg.OrderId, channel);
                    }
                    else if (msg.OrderType == OrderType.住院预缴金订单)
                    {
                        return ProcessInpatientPrepayOrder(msg.OrderId, channel);
                    }

                    return new ConsumedResult { Ack = true };
                });

                while (true)
                {
                    if (ct.IsCancellationRequested)
                    {
                        break;
                    }

                    Thread.Sleep(50);
                }
            }
        }

        private ConsumedResult ProcessRegOrder(int orderId, WrapperChannel channel)
        {
            OrderSummary order;
            using (var ctx = new GdsfybjyWeiXinEntities())
            {
                order = ctx.ApptOrders.Where(x => x.Id == orderId).
                    Select(x => new OrderSummary
                    {
                        OrderStatus = x.OrderStatus,
                        PayState = x.PayState,
                        Id = x.Id,
                        WxTransactionId = x.WxTransactionId,
                        OrderNo = x.OrderNo,
                        SumFee = x.SumFee
                    }).FirstOrDefault();
                if (order == null)
                {
                    return new ConsumedResult
                    {
                        Ack = true
                    };
                }
            }

            //退款中
            DataBaseCommandFactory.CreateDatbaseCommand().Refunding(orderId);
            try
                {
                    WapPayRefundResponse refundResult = WapPayment.WapPayRefund(new WapPayRefundRequest
                    {

                        NotifyUrl = ConfigurationManager.AppSettings["AlipayNotify"] +"Reg/PaySucceed",
                        BatchNo = DateTime.Now.ToString("yyyyMMddhhmmss") + DateTime.Now.Millisecond,
                        RefundDate = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"),
                        BatchNum = "1",
                        DetailData = order.WxTransactionId + "^" + order.SumFee + "^取号失败而退款"
                    });
                    if (refundResult.ResultCode == "0" && refundResult.IsSuccess == "T")
                    {
                        // 退款成功
                        DataBaseCommandFactory.CreateDatbaseCommand().RefundSuccess(orderId, order.WxTransactionId);

                        // RMQ 发送用户退费成功通知
                        var msgProducer = new UserMessageProducer();
                        msgProducer.Publish(new UserMessageMsg
                        {
                            Type = UserMessageType.挂号失败退费成功通知,
                            OrderId = order.Id
                        });
                    }
                    else
                    {
                        // 退款失败
                        DataBaseCommandFactory.CreateDatbaseCommand().RefundError(orderId);
                    }
                }
                catch (Exception ex)
                {
                    Logger.ErrorFormat("调用第三方支付退款Api出错,信息：{0}", JsonConvert.SerializeObject(ex));
                    return new ConsumedResult
                    {
                        Ack = false,
                        Delay = 1000
                    };
                }

            return new ConsumedResult
            {
                Ack = true
            };
        }

        private ConsumedResult ProcessBillOrder(int orderId, WrapperChannel channel)
        {
            using (var ctx = new GdsfybjyWeiXinEntities())
            {
                var order = ctx.BillOrders.FirstOrDefault(x => x.Id == orderId);
                if (order == null)
                {
                    return new ConsumedResult
                    {
                        Ack = true
                    };
                }

                // 退款中
                order.OrderStatus = BillOrderExtensions.OrderStatus.退款中.ToInt32();
                order.PayState = BillOrderExtensions.PayState.退款中.ToInt32().ToString();
                order.Remark = "缴费失败而退款";
                ctx.SaveChanges();

                var payFee = 0m;
                if (order.YiBaoStatus == BillOrderExtensions.YiBaoStatus.使用了医保.ToInt32()
                    && !string.IsNullOrEmpty(order.YiBaoJydjh))
                {
                    payFee = order.PersonalMoney.GetValueOrDefault();
                }
                else
                {
                    payFee = order.PrescMoney.GetValueOrDefault();
                }
                //找到支付通知日志
                var payNotifyLog = ctx.WxPayNotifyLogs.FirstOrDefault(x => x.TransactionId == order.WxTransactionId && x.TradeState == 1);
                payFee = (payNotifyLog?.TotalFee / 100.0)?.ToDecimalOrDefault() ?? payFee;

                try
                {
                    if (order.AliPayType == "WAP")
                    {
                        //WAP缴费退款
                        WapPayRefundResponse refundResult = WapPayment.WapPayRefund(new WapPayRefundRequest
                        {

                            NotifyUrl = ConfigurationManager.AppSettings["AlipayNotify"] + "Bill/WapPayFail",
                            BatchNo = DateTime.Now.ToString("yyyyMMddhhmmss") + DateTime.Now.Millisecond,
                            RefundDate = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"),
                            BatchNum = "1",
                            DetailData = order.WxTransactionId + "^" + payFee + "^缴费失败而退款"
                        });

                        if (refundResult.ResultCode == "0" && refundResult.IsSuccess == "T")
                        {
                            //异步接受通知知道退款成功结果
                            // 退款成功
                            order.OrderStatus = BillOrderExtensions.OrderStatus.退款成功.ToInt32();
                            order.PayState = BillOrderExtensions.PayState.已退款.ToInt32().ToString();
                            order.RefundTime = DateTime.Now;
                            order.WxRefundId = order.WxTransactionId;
                            ctx.SaveChanges();

                            // RMQ 发送用户退费成功通知
                            var messageProducer = new UserMessageProducer();
                            messageProducer.Publish(new UserMessageMsg
                            {
                                OrderId = order.Id,
                                Type = UserMessageType.缴费失败退款成功通知
                            });
                        }
                        else
                        {
                            // 退款失败
                            order.OrderStatus = BillOrderExtensions.OrderStatus.退款失败.ToInt32();
                            order.PayState = BillOrderExtensions.PayState.退款失败.ToInt32().ToString();
                            ctx.SaveChanges();
                        }
                    }

                    else
                    {
                        //当面付退款
                        PrecreatePayment payment = new PrecreatePayment();
                        AcquireRefundResponse wapPayRefundResponse = payment.AcquireRefund(new AcquireRefundRequest
                        {
                            TradeNo = order.WxTransactionId,
                            BatchNo = DateTime.Now.ToString("yyyyMMddhhmmss") + DateTime.Now.Millisecond,
                            RefundAmount = payFee,
                            RefundReason = "缴费失败而退款",
                            OutTradeNo = "BL" + order.OrderNo
                        });

                        if (wapPayRefundResponse.ResultCode == "0" && wapPayRefundResponse.IsSuccess == "T")
                        {
                            // 退款成功
                            order.OrderStatus = BillOrderExtensions.OrderStatus.退款成功.ToInt32();
                            order.PayState = BillOrderExtensions.PayState.已退款.ToInt32().ToString();
                            order.RefundTime = wapPayRefundResponse.GmtRefundPay.ToDateTimeOrDefault();
                            order.WxRefundId = wapPayRefundResponse.TradeNo;
                            ctx.SaveChanges();

                            // RMQ 发送用户退费成功通知
                            var messageProducer = new UserMessageProducer();
                            messageProducer.Publish(new UserMessageMsg
                            {
                                OrderId = order.Id,
                                Type = UserMessageType.缴费失败退款成功通知
                            });
                        }
                        else
                        {
                            // 退款失败
                            order.OrderStatus = BillOrderExtensions.OrderStatus.退款失败.ToInt32();
                            order.PayState = BillOrderExtensions.PayState.退款失败.ToInt32().ToString();
                            ctx.SaveChanges();
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logger.ErrorFormat("调用第三方支付退款Api出错,信息：{0}", JsonConvert.SerializeObject(ex));
                    return new ConsumedResult
                    {
                        Ack = false,
                        Delay = 1000
                    };
                }


                #region 支付宝没医保缴费
                // 医保退费
                if (order.YiBaoStatus == BillOrderExtensions.YiBaoStatus.使用了医保.ToInt32()
                    && !string.IsNullOrEmpty(order.YiBaoJydjh))
                {
                    order.YiBaoStatus = BillOrderExtensions.YiBaoStatus.取消医保中.ToInt32();
                    ctx.SaveChanges();

                    // 执行医保退费操作
                    var ybReturnRequest = new YBReturnChargesRequest();
                    ybReturnRequest.CardNo = order.CardNo;
                    ybReturnRequest.Jydjh = order.YiBaoJydjh;

                    try
                    {
                        var httpClient = InHttpClient.GetClient();
                        var responseMsg = httpClient.PostAsJsonAsync("HisSp/YBReturnCharges", ybReturnRequest).Result;
                        responseMsg.EnsureSuccessStatusCode();
                        var ybReturnResponse = responseMsg.Content.ReadAsAsync<YBReturnChargesResponse>().Result;
                        if (ybReturnResponse.ResultCode != "0")
                        {
                            order.YiBaoStatus = BillOrderExtensions.YiBaoStatus.取消医保失败.ToInt32();
                            ctx.SaveChanges();
                        }
                        else
                        {
                            order.YiBaoStatus = BillOrderExtensions.YiBaoStatus.取消了医保.ToInt32();
                            ctx.SaveChanges();
                        }
                    }
                    catch (Exception ex)
                    {
                        Logger.ErrorFormat("调用院内医保退费Api出错,信息：{0}", JsonConvert.SerializeObject(ex));

                        order.YiBaoStatus = BillOrderExtensions.YiBaoStatus.取消医保失败.ToInt32();
                        ctx.SaveChanges();
                    }
                }
                #endregion
            }

            return new ConsumedResult
            {
                Ack = true
            };
        }

        private ConsumedResult ProcessInpatientPrepayOrder(int orderId, WrapperChannel channel)
        {
            using (var ctx = new GdsfybjyWeiXinEntities())
            {
                var order = ctx.InpatientPrepayOrders.FirstOrDefault(x => x.Id == orderId);
                if (order == null)
                {
                    return new ConsumedResult
                    {
                        Ack = true
                    };
                }

                // 退款中
                order.OrderStatus = PrepayOrderExtensions.OrderStatus.退款中.ToInt32();
                order.PayState = PrepayOrderExtensions.PayState.退款中.ToInt32().ToString();
                order.Remark = "充值失败而退款";
                ctx.SaveChanges();

                var prepayMoney = order.PrepayMoney.GetValueOrDefault();
                //找到支付通知日志
                var payNotifyLog = ctx.WxPayNotifyLogs.FirstOrDefault(x => x.TransactionId == order.WxTransactionId && x.TradeState == 1);
                prepayMoney = (payNotifyLog?.TotalFee / 100.0)?.ToDecimalOrDefault() ?? prepayMoney;

                try
                {
                    if (order.AliPayType == "WAP")
                    {
                        //WAP缴费退款
                        WapPayRefundResponse refundResult = WapPayment.WapPayRefund(new WapPayRefundRequest
                        {
                            NotifyUrl = ConfigurationManager.AppSettings["AlipayNotify"] + "Bill/WapPayFail",
                            BatchNo = DateTime.Now.ToString("yyyyMMddhhmmss") + DateTime.Now.Millisecond,
                            RefundDate = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"),
                            BatchNum = "1",
                            DetailData = order.WxTransactionId + "^" + prepayMoney + "^充值失败而退款"
                        });
                        if (refundResult.ResultCode == "0" && refundResult.IsSuccess == "T")
                        {
                            //异步接受通知知道退款成功结果
                            // 退款成功
                            order.OrderStatus = PrepayOrderExtensions.OrderStatus.退款成功.ToInt32();
                            order.Remark = "充值失败而退款";
                            order.PayState = PrepayOrderExtensions.PayState.已退款.ToInt32().ToString();
                            order.RefundTime = DateTime.Now;
                            order.WxRefundId = order.WxTransactionId;
                            ctx.SaveChanges();

                            // RMQ 发送用户退费成功通知
                            var msgProducer = new UserMessageProducer();
                            msgProducer.Publish(new UserMessageMsg
                            {
                                Type = UserMessageType.住院预缴金失败退费成功通知,
                                OrderId = order.Id
                            });
                        }
                        else
                        {
                            // 退款失败
                            order.OrderStatus = PrepayOrderExtensions.OrderStatus.退款失败.ToInt32();
                            order.PayState = PrepayOrderExtensions.PayState.退款失败.ToInt32().ToString();
                            ctx.SaveChanges();
                        }
                    }
                    else
                    {
                        //当面付退款
                        PrecreatePayment payment = new PrecreatePayment();
                        AcquireRefundResponse wapPayRefundResponse = payment.AcquireRefund(new AcquireRefundRequest
                        {
                            TradeNo = order.WxTransactionId,
                            BatchNo = DateTime.Now.ToString("yyyyMMddhhmmss") + DateTime.Now.Millisecond,
                            RefundAmount = prepayMoney,
                            RefundReason = "充值失败而退款",
                            OutTradeNo = "IP" + order.OrderNo
                        });

                        if (wapPayRefundResponse.ResultCode == "0" && wapPayRefundResponse.IsSuccess == "T")
                        {
                            // 退款成功
                            order.OrderStatus = PrepayOrderExtensions.OrderStatus.退款成功.ToInt32();
                            order.Remark = "充值失败而退款";
                            order.PayState = PrepayOrderExtensions.PayState.已退款.ToInt32().ToString();
                            order.RefundTime = wapPayRefundResponse.GmtRefundPay.ToDateTimeOrDefault();
                            order.WxRefundId = wapPayRefundResponse.TradeNo;
                            ctx.SaveChanges();

                            // RMQ 发送用户退费成功通知
                            var msgProducer = new UserMessageProducer();
                            msgProducer.Publish(new UserMessageMsg
                            {
                                Type = UserMessageType.住院预缴金失败退费成功通知,
                                OrderId = order.Id
                            });
                        }
                        else
                        {
                            // 退款失败
                            order.OrderStatus = PrepayOrderExtensions.OrderStatus.退款失败.ToInt32();
                            order.PayState = PrepayOrderExtensions.PayState.退款失败.ToInt32().ToString();
                            ctx.SaveChanges();
                        }
                    }

                }
                catch (Exception ex)
                {
                    Logger.ErrorFormat("调用第三方支付退款Api出错,信息：{0}", JsonConvert.SerializeObject(ex));
                    return new ConsumedResult
                    {
                        Ack = false,
                        Delay = 1000
                    };
                }

            }

            return new ConsumedResult
            {
                Ack = true
            };
        }

        public class OrderSummary
        {
            public int OrderStatus { get; set; }
            public string PayState { get; set; }
            public int Id { get; set; }
            public string WxTransactionId { get; set; }
            public string OpenId { get; set; }
            public string OrderNo { get; set; }
            public decimal? SumFee { get; set; }
        }
    }


}